package team.seekers.hula.course.resource.examSubmit.service;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import team.seekers.hula.common.entity.result.ApiExceptionEnum;
import team.seekers.hula.common.utils.AssertUtils;
import team.seekers.hula.common.utils.BaseConvertUtils;
import team.seekers.hula.course.courseUser.service.CourseUserService;
import team.seekers.hula.course.resource.exam.entity.dto.ExamProblemDTO;
import team.seekers.hula.course.resource.exam.entity.dto.ExamQueryDTO;
import team.seekers.hula.course.resource.exam.service.ExamService;
import team.seekers.hula.course.resource.examSubmit.dao.ExamRecordDao;
import team.seekers.hula.course.resource.examSubmit.entity.dao.ExamRecordDO;
import team.seekers.hula.course.resource.examSubmit.entity.dto.ExamRecordCreateDTO;
import team.seekers.hula.course.resource.examSubmit.entity.dto.ExamRecordDTO;
import team.seekers.hula.course.resource.examSubmit.entity.dto.ProblemSubmission;
import team.seekers.hula.course.resource.problem.entity.dto.ProblemDTO;
import team.seekers.hula.course.resource.problem.service.ProblemService;
import team.seekers.hula.course.resource.problemSubmit.entity.dto.SubmissionDTO;
import team.seekers.hula.course.resource.problemSubmit.service.SubmissionService;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * date: 2022/5/9 11:29
 *
 * @author GH
 * QQ 1124813753
 */
@Service
public class ExamRecordManageService {

    @Autowired
    private ExamRecordDao examRecordDao;

    @Autowired
    private ExamService examService;

    @Autowired
    private SubmissionService submissionService;

    @Autowired
    private ProblemService problemService;

    @Autowired
    private CourseUserService courseUserService;



    @Transactional(rollbackFor = Exception.class)
    public String participateExam(String examId, String userId) {
        ExamQueryDTO examQueryDTO = examService.queryById(examId);
        Integer count = examRecordDao.lambdaQuery()
                .eq(ExamRecordDO::getExamId, examId)
                .eq(ExamRecordDO::getUserId, userId)
                .count();
        AssertUtils.isTrue(examQueryDTO.getLimitTime() > count, ApiExceptionEnum.EXAM_TIME_OUT);
        ExamRecordDO examRecordDO = ExamRecordDO.builder()
                .examId(examId)
                .userId(userId)
                .count(count+1)
                .build();
        examRecordDao.save(examRecordDO);
        return examRecordDO.getId();
    }

    @Transactional(rollbackFor = Exception.class)
    public void examSubmit(ExamRecordCreateDTO createDTO) {
        ExamRecordDO examRecordDO = examRecordDao.getById(createDTO.getExamRecordId());

        ArrayList<String> problemIds = new ArrayList<>();
        for (ProblemSubmission submission : createDTO.getSubmissions()) {
            problemIds.add(submission.getProblemId());
        }

        // 远端获取problem信息
        Map<String, ProblemDTO> problemDtoMap = problemService.idsMapDTO(problemIds);

        Map<String, ExamProblemDTO> problemCriteriaMap = examService.idToProblemDTOMap(examRecordDO.getExamId());
        for (ProblemSubmission submission : createDTO.getSubmissions()) {
            ProblemDTO problemDTO = problemDtoMap.get(submission.getProblemId());
            submission.setOptions(problemDTO.getOptions());
            submission.setRightAnswer(problemDTO.getAnswer());
            submission.setProblemType(problemDTO.getType());
            submission.setCriteria(problemCriteriaMap.get(submission.getProblemId()).getCriteria());
        }


        List<SubmissionDTO> submissions = createDTO.getSubmissions().stream().map(pSubmit ->
                SubmissionDTO.builder()
                        .pId(pSubmit.getProblemId())
                        .uId(examRecordDO.getUserId())
                        .exId(examRecordDO.getExamId())
                        .ipv4(createDTO.getIpv4())
                        .result(pSubmit.getAnswer())
                        .score(SubmissionDTO.judge(pSubmit.getRightAnswer(), pSubmit.getCriteria(), pSubmit.getAnswer(), pSubmit.getProblemType()))
                        .build()
        ).collect(Collectors.toList());

        submissionService.saveOrUpdateBatch(submissions);
        examRecordDO.setSubmissions(BaseConvertUtils.objectListToBytes(createDTO.getSubmissions()));

        Double score = submissions.stream().mapToDouble(SubmissionDTO::getScore).sum();
        examRecordDO.setScore(score.floatValue());

        examRecordDO.setStatus(1);
        examRecordDao.updateById(examRecordDO);

        ExamQueryDTO examQueryDTO = examService.queryById(examRecordDO.getExamId());
        if(examQueryDTO.getType() == 1){
            // 期末考试，同步课程记录
            courseUserService.updateCourseScore(examQueryDTO.getCourseId(),examRecordDO.getUserId(),score.intValue());
        }
    }

    /**
     * 查询测试提交记录
     */
    public List<ExamRecordDTO> list(Long examId, Long userId) {
        return ExamRecordDO.toDTOList(examRecordDao.lambdaQuery().select(
                        ExamRecordDO::getId,
                        ExamRecordDO::getScore,
                        ExamRecordDO::getSubmissions,
                        ExamRecordDO::getGmtCreate
                ).eq(ExamRecordDO::getExamId, examId)
                .eq(ExamRecordDO::getUserId, userId)
                .orderByAsc(ExamRecordDO::getGmtCreate).list());
    }

    /**
     * 查询某个测试的某次提交的所有题目提交
     */
    public List<ProblemSubmission> queryExamSubmission(Long examRecordId) {
        ExamRecordDO examRecordDO = examRecordDao.lambdaQuery()
                .select(ExamRecordDO::getSubmissions)
                .eq(ExamRecordDO::getId, examRecordId)
                .one();
        AssertUtils.notNull(examRecordDO, ApiExceptionEnum.DB_FAIL);
        return BaseConvertUtils.bytesToObjectList(examRecordDO.getSubmissions());
    }


//    public List<List<ExamQueryDTO>> listChapterExamByCourseId(String courseId, String userId) {
//        return examService.listChapterExamByCourseId(courseId,userId);
//    }

    public List<ExamQueryDTO> listFinalExamByCourseId(String courseId, String userId) {
        return examService.listFinalExamByCourseId(courseId,userId);
    }
}
